#pragma once

#include <iostream>

#ifdef __cplusplus
extern "C" {
#endif

#include <CL/cl.h>

#ifdef __cplusplus
}
#endif

#ifndef NS_CLPP_BEGIN

#define NS_CLPP_BEGIN namespace clpp {

#endif

#ifndef NS_CLPP_END

#define NS_CLPP_END };

#endif

NS_CLPP_BEGIN

struct ICLObject
{
	virtual void AddRef() = 0;

	virtual void Release() = 0;

	virtual unsigned long RefCount() = 0;
};

template <class T>
class CLObjectGuard
{
public:
	CLObjectGuard() :
		m_GuardObject(nullptr)
	{}

	CLObjectGuard(T * clObject) :
		m_GuardObject(clObject)
	{
	}

	CLObjectGuard(const CLObjectGuard & guard) :
		m_GuardObject(guard.m_GuardObject)
	{
		this->m_GuardObject->AddRef();
	}

	virtual ~CLObjectGuard()
	{
		// cout << "~CLObjectGuard" << endl;

		if (this->m_GuardObject != nullptr)
		{
			this->m_GuardObject->Release();
		}
	}

public:
	CLObjectGuard & operator = (T * clObject)
	{
		if (this->m_GuardObject != nullptr)
		{
			this->m_GuardObject->Release();
		}

		this->m_GuardObject = clObject;
		
		return (*this);
	}

	CLObjectGuard & operator = (const CLObjectGuard & guard)
	{
		if (this->m_GuardObject != nullptr)
		{
			this->m_GuardObject->Release();
		}

		this->m_GuardObject = guard.m_GuardObject;
		this->m_GuardObject->AddRef();

		return (*this);
	}

	T * operator ->()
	{
		return m_GuardObject;
	}

	T * get()
	{
		return m_GuardObject;
	}

private:
	T * m_GuardObject;
};

NS_CLPP_END